/*
 * Copyright (c) 2011, Nikolaus Moll
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * * Neither the name of the gradecalculator.net nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */
package net.gradecalculator.core;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import net.gradecalculator.core.adapted.AdaptedModule;
import net.gradecalculator.core.interfaces.IStudent;
import net.gradecalculator.core.interfaces.IStudyRegulations;
import net.gradecalculator.core.interfaces.results.IResult;
import net.gradecalculator.core.interfaces.results.IResultType;
import net.gradecalculator.plugin.grade.interfaces.IGradeFactory;
import net.gradecalculator.plugin.grade.interfaces.IOverallGrade;

public class AdaptedRegulations {

	private class Result {
		private IOverallGrade grade;
		private float ects;
	}

	private final List<AdaptedModule> modules;
	private final IStudent student;

	private final Result[] results;

	private volatile int spoECTS = 0;
	private List<IResult> unassignedResults;
	private final IGradeFactory fab;

	public AdaptedRegulations(final IStudent student) {
		this.student = student;

		fab = GradeFactoryUtil.getInstance().getFab(student.getUniversity().getCountryCode());
		modules = new ArrayList<AdaptedModule>();
		unassignedResults = new ArrayList<IResult>();

		results = new Result[student.getResultTypes().size()];
		for (int i = 0; i < results.length; i++) {
			results[i] = new Result();
		}
	}

	public IStudent getStudent() {
		return student;
	}

	public void addModule(final AdaptedModule module) {
		modules.add(module);
	}

	public List<AdaptedModule> getModules() {
		// make working copy
		final ArrayList<AdaptedModule> result = new ArrayList<AdaptedModule>(modules);
		//Collections.sort(result);
		return result;
	}

	public String getName() {
		return "student's spo";
	}

	private void update() {
		for (final IResultType r : student.getResultTypes()) {
			results[r.ordinal()].ects = 0;
			results[r.ordinal()].grade = fab.createOverallGrade();
		}

		if (student.getUniversity() == null) {
			// nothing to do
			return;
		}

		for (final AdaptedModule m : modules) {

			for (final IResultType r : student.getResultTypes()) {
				final float ects = m.getECTS(r);

				if (m.isGraded(r)) {
					results[r.ordinal()].grade.add(m.getGrade(r), ects);
				}

				results[r.ordinal()].ects += ects;
			}
		}
	}

	public float getECTS(final IResultType passed) {
		update();
		return results[passed.ordinal()].ects;
	}

	public String getGrade(final IResultType passed) {
		update();

		final IOverallGrade grade = results[passed.ordinal()].grade;

		if (grade == null) {
			return "";
		}

		return grade.getGrade();
	}

	public int getSPOECTS() {
		int result = spoECTS;
		if (result == 0) {
			for (final AdaptedModule m : modules) {
				result += m.getModule().getECTS();
			}

			spoECTS = result;
		}
		return result;
	}

	public List<IResult> getUnassignedResults() {
		return unassignedResults;
	}

	public void setUnassignedResults(final List<IResult> results) {
		unassignedResults = new LinkedList<IResult>();
		for (final IResult result : results) {
			if (result.getCourse() == null) {
				unassignedResults.add(result);
			}
		}
	}

	/**
	 * Removes the result from list of unassigned results. Does not remove the
	 * result from the student.
	 * 
	 * @param result
	 */
	public void removeUnassignedResult(final IResult result) {
		unassignedResults.remove(result);
	}

	public IResult getUnassignedResult(final String courseName) {
		//		for (final IResult result : unassignedResults) {
		//			if (result.getCourseIdentifier().equals(courseName)) {
		//				return result;
		//			}
		//		}
		return null;
	}

	public IGradeFactory getGradeFactory() {
		return fab;
	}

	public IStudyRegulations getRegulations() {
		return student.getRegulations();
	}

}
